package de.ipk_gatersleben.bit.bi.edal.publication.metadata;

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.rmi.RemoteException;
import java.security.AccessControlException;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.swing.JProgressBar;

import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataDirectoryException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataEntityVersionException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.EnumDublinCoreElements;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaData;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaDataException;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataDirectory;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataEntity;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataFile;

/**
 * Implementation of {@link FileVisitor} to walk a file system tree and store
 * the object into eDAL.
 * 
 * @author arendd
 */
public class PublicationDirectoryVisitorRmi2 implements FileVisitor<Path> {

	private SortedSet<String> pathSet = new TreeSet<String>();
	private ClientPrimaryDataDirectory currentDirectory = null;
	private StringBuffer pathString = new StringBuffer("");
	private int numberOfRootElements = 0;
	private String indent = "";
	private MetaData metaData;
	private ClientPrimaryDataDirectory directoryToPublish = null;
	private JProgressBar overallProgressBar;
	private JProgressBar fileProgressBar;
	private Boolean update = false;

	public ClientPrimaryDataDirectory getRootDirectoryToPublish() {
		return directoryToPublish;
	}

	public PublicationDirectoryVisitorRmi2(JProgressBar overallProgressBar,
			JProgressBar fileProgressBar,
			ClientPrimaryDataDirectory currentDirectory, Path path,
			MetaData metaData, Boolean update) {

		this.currentDirectory = currentDirectory;
		this.numberOfRootElements = path.getNameCount() - 1;
		this.metaData = metaData;
		this.overallProgressBar = overallProgressBar;
		this.fileProgressBar = fileProgressBar;
		this.update = update;

		try {

			ClientPrimaryDataDirectory newCurrentDirectory = null;

			if (update
					&& this.currentDirectory.exist(this.metaData
							.getElementValue(EnumDublinCoreElements.TITLE)
							.toString())) {

				newCurrentDirectory = (ClientPrimaryDataDirectory) this.currentDirectory
						.getPrimaryDataEntity(this.metaData.getElementValue(
								EnumDublinCoreElements.TITLE).toString());

			}

			else {

				newCurrentDirectory = this.currentDirectory
						.createPrimaryDataDirectory(this.metaData
								.getElementValue(EnumDublinCoreElements.TITLE)
								.toString());

			}

			setMetaData(newCurrentDirectory);

			this.currentDirectory = newCurrentDirectory;

			this.directoryToPublish = newCurrentDirectory;

		} catch (RemoteException | PrimaryDataDirectoryException
				| MetaDataException e) {
			e.printStackTrace();
		}
	}

	@Override
	public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
			throws IOException {

		pathString.append(indent + dir.getFileName() + "\n");
		indent += "  ";
		try {
			ClientPrimaryDataDirectory newCurrentDirectory = null;

			if (update
					&& this.currentDirectory
							.exist(dir.getFileName().toString())) {

				newCurrentDirectory = (ClientPrimaryDataDirectory) this.currentDirectory
						.getPrimaryDataEntity(dir.getFileName().toString());
				// } else {
				// newCurrentDirectory = this.currentDirectory
				// .createPrimaryDataDirectory(dir.getFileName()
				// .toString());
				// }

			} else {
				newCurrentDirectory = this.currentDirectory
						.createPrimaryDataDirectory(dir.getFileName()
								.toString());
			}

			setMetaData(newCurrentDirectory);

			this.currentDirectory = newCurrentDirectory;

		} catch (AccessControlException | PrimaryDataDirectoryException e) {
			e.printStackTrace();
		}
		/* else rootDirectory */
		if (numberOfRootElements < dir.getNameCount()) {

			Path tmpPath = dir
					.subpath(numberOfRootElements, dir.getNameCount());

			StringBuffer tmpBuffer = new StringBuffer("//");

			for (int i = 0; i < tmpPath.getNameCount(); i++) {
				tmpBuffer.append(tmpPath.getName(i) + "/");
			}
			/* cut last "/"-symbol */
			pathSet.add(tmpBuffer.toString().substring(0,
					tmpBuffer.toString().length() - 1));
		}
		return FileVisitResult.CONTINUE;
	}

	@Override
	public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
			throws IOException {

		pathString.append(indent + file.getFileName() + "\n");

		try {
			ClientPrimaryDataFile clientPrimaryDataFile = null;

			if (update
					&& this.currentDirectory.exist(file.getFileName()
							.toString())) {

				clientPrimaryDataFile = (ClientPrimaryDataFile) this.currentDirectory
						.getPrimaryDataEntity(file.getFileName().toString());

			} else {
				clientPrimaryDataFile = this.currentDirectory
						.createPrimaryDataFile((file.getFileName().toString()));
			}

			setMetaData(clientPrimaryDataFile);

			FileStoreSwingWorker worker = new FileStoreSwingWorker(
					this.fileProgressBar, file, clientPrimaryDataFile);

			worker.execute();

			this.overallProgressBar
					.setValue(this.overallProgressBar.getValue() + 1);

		} catch (AccessControlException | PrimaryDataDirectoryException e) {
			e.printStackTrace();
		}
		Path tmpPath = file.subpath(numberOfRootElements, file.getNameCount());

		StringBuffer tmpBuffer = new StringBuffer("//");

		for (int i = 0; i < tmpPath.getNameCount(); i++) {
			tmpBuffer.append(tmpPath.getName(i) + "/");
		}

		/* cut last "/"-symbol */
		pathSet.add(tmpBuffer.toString().substring(0,
				tmpBuffer.toString().length() - 1));
		return FileVisitResult.CONTINUE;
	}

	@Override
	public FileVisitResult visitFileFailed(Path file, IOException exc)
			throws IOException {
		return FileVisitResult.CONTINUE;
	}

	@Override
	public FileVisitResult postVisitDirectory(Path dir, IOException exc)
			throws IOException {
		try {
			this.currentDirectory = this.currentDirectory.getParentDirectory();
		} catch (AccessControlException | PrimaryDataDirectoryException e) {
			e.printStackTrace();
		}

		indent = indent.substring(2);
		return FileVisitResult.CONTINUE;
	}

	public StringBuffer getInput() {
		return pathString;
	}

	public SortedSet<String> getPathSet() {
		return pathSet;
	}

	private void setMetaData(ClientPrimaryDataEntity entity) {

		try {
			MetaData metaDataFile = entity.getMetaData().clone();

			metaDataFile.setElementValue(EnumDublinCoreElements.CREATOR,
					this.metaData
							.getElementValue(EnumDublinCoreElements.CREATOR));
			metaDataFile
					.setElementValue(
							EnumDublinCoreElements.CONTRIBUTOR,
							this.metaData
									.getElementValue(EnumDublinCoreElements.CONTRIBUTOR));
			metaDataFile.setElementValue(EnumDublinCoreElements.SUBJECT,
					this.metaData
							.getElementValue(EnumDublinCoreElements.SUBJECT));
			metaDataFile.setElementValue(EnumDublinCoreElements.LANGUAGE,
					this.metaData
							.getElementValue(EnumDublinCoreElements.LANGUAGE));
			metaDataFile
					.setElementValue(
							EnumDublinCoreElements.DESCRIPTION,
							this.metaData
									.getElementValue(EnumDublinCoreElements.DESCRIPTION));
			metaDataFile.setElementValue(EnumDublinCoreElements.PUBLISHER,
					this.metaData
							.getElementValue(EnumDublinCoreElements.PUBLISHER));

			entity.setMetaData(metaDataFile);

		} catch (RemoteException | CloneNotSupportedException
				| MetaDataException | PrimaryDataEntityVersionException e) {
			e.printStackTrace();
		}

	}
}